package cn.org.wangchangjiu.table2entity.ui;

import cn.org.wangchangjiu.table2entity.action.OpenPathConfigSettingAction;
import cn.org.wangchangjiu.table2entity.extension.PathConfigSettingCache;
import cn.org.wangchangjiu.table2entity.model.CodePathConfig;
import cn.org.wangchangjiu.table2entity.model.MapperXml;
import cn.org.wangchangjiu.table2entity.model.RepositoryInfo;
import cn.org.wangchangjiu.table2entity.model.TableInfo;
import cn.org.wangchangjiu.table2entity.service.CreateTableParser;
import cn.org.wangchangjiu.table2entity.service.JpaRepositoryParser;
import cn.org.wangchangjiu.table2entity.service.MyBatisPlusParser;
import cn.org.wangchangjiu.table2entity.util.CommonUtil;
import cn.org.wangchangjiu.table2entity.util.LocalFileUtils;
import cn.org.wangchangjiu.table2entity.util.VelocityUtils;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.ide.highlighter.XmlFileType;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import org.apache.commons.lang3.StringUtils;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;

public class CreateTableCodeDialog extends JDialog {
    private JPanel contentPane;
    private JButton buttonOK;
    private JLabel codeInputLabel;
    private JTextArea code;
    private JCheckBox jpaEntityCheckBox;
    private JCheckBox mybatisPlusEntityCheckBox;
    private JCheckBox jpaRepositoryCheckBox;
    private JCheckBox mybatisMapperCheckBox;

    private boolean jpaEntityCheck(String path){
        return this.jpaEntityCheckBox.isSelected() && StringUtils.isEmpty(path);
    }

    private boolean jpaRepositoryCheck(String path){
        return this.jpaRepositoryCheckBox.isSelected() && StringUtils.isEmpty(path);
    }

    private boolean mybatisPlusEntityCheck(String path){
        return this.mybatisPlusEntityCheckBox.isSelected() && StringUtils.isEmpty(path);
    }

    private boolean mybatisMapperCheck(String path, String xmlPath){
        return this.mybatisMapperCheckBox.isSelected() && (StringUtils.isEmpty(path) || StringUtils.isEmpty(xmlPath));
    }

    private boolean allCheck(){
        return (jpaCheck() && myBatisCheck());
    }

    private boolean jpaCheck(){
        return (this.jpaEntityCheckBox.isSelected() && this.mybatisMapperCheckBox.isSelected());
    }

    private boolean myBatisCheck(){
        return (this.mybatisPlusEntityCheckBox.isSelected() && this.jpaRepositoryCheckBox.isSelected());
    }

    public CreateTableCodeDialog(AnActionEvent anActionEvent) {
        setContentPane(contentPane);
        setTitle("table2Entity");
        setSize(800, 700);
        setLocation(600, 200);
        setModal(true);
        setResizable(true);
        getRootPane().setDefaultButton(buttonOK);

        PathConfigSettingCache state = PathConfigSettingCache.getInstance(anActionEvent.getProject());
        Project project = anActionEvent.getProject();
        if(state == null || state.getConfig() == null ){
            configureMessageReminders(project);
            return;

        }
        CodePathConfig config = state.getConfig();
        this.jpaEntityCheckBox.setSelected(config.isGenerateJpa());
        this.jpaRepositoryCheckBox.setSelected(config.isGenerateJpa());
        this.mybatisPlusEntityCheckBox.setSelected(config.isGenerateMyBatisPlus());
        this.mybatisMapperCheckBox.setSelected(config.isGenerateMyBatisPlus());


        // 监听事件
        buttonOK.addActionListener(e -> {
            buttonOK.setEnabled(false);
            String createTableSQLText = code.getText();
            if (userOperateNoPass(project, config, createTableSQLText)) {
                return;
            }

            TableInfo result = null;
            if(this.jpaEntityCheckBox.isSelected()){
                // 生成 jpa entity
                try {
                    result = CreateTableParser.parserJpaEntity(createTableSQLText);
                    result.setClassPackage(CommonUtil.pathToImportPackage(config.getEntityPath() + "/" + result.getEntityName()));
                    result.setPackagePath(CommonUtil.pathToDeclarePackage(config.getEntityPath()));
                    result.setCodeAuthor(config.getCodeAuthor());
                    String generateCode = VelocityUtils.generateEntity(result, "template/jpa/entity.java.vm");
                    LocalFileUtils.writeFile(anActionEvent, project, CommonUtil.pathToPackage(config.getEntityPath()), result.getEntityName() + ".java", generateCode, JavaFileType.INSTANCE);

                } catch (Exception ex){
                    Messages.showMessageDialog(ex.getMessage(), "error massage:", Messages.getErrorIcon());
                    return;
                }
            }

            if(this.jpaRepositoryCheckBox.isSelected()){
                try {
                    // jpa Repository
                    RepositoryInfo repositoryInfo = JpaRepositoryParser.parser(result);
                    repositoryInfo.setCodeAuthor(config.getCodeAuthor());
                    repositoryInfo.setPackagePath(CommonUtil.pathToDeclarePackage(config.getDaoPath()));
                    String generateCode = VelocityUtils.generateDao(repositoryInfo, "template/jpa/repository.java.vm");
                    LocalFileUtils.writeFile(anActionEvent, project, CommonUtil.pathToPackage(config.getDaoPath()), repositoryInfo.getRepositoryName() + ".java", generateCode, JavaFileType.INSTANCE);

                } catch (Exception ex){
                    Messages.showMessageDialog(ex.getMessage(), "error massage:", Messages.getErrorIcon());
                    return;
                }
            }

            if(this.mybatisPlusEntityCheckBox.isSelected()){
                // 生成 mybatis-plus entity
                try {
                    result = CreateTableParser.parserMyBatisPlusEntity(createTableSQLText);
                    result.setPackagePath(CommonUtil.pathToDeclarePackage(config.getMyBatisEntityPath()));
                    result.setClassPackage(CommonUtil.pathToImportPackage(config.getMyBatisEntityPath() + "/" + result.getEntityName()));
                    result.setCodeAuthor(config.getCodeAuthor());
                    String generateCode = VelocityUtils.generateEntity(result, "template/mybatis-plus/entity.java.vm");
                    LocalFileUtils.writeFile(anActionEvent, project, CommonUtil.pathToPackage(config.getMyBatisEntityPath()), result.getEntityName() + ".java", generateCode, JavaFileType.INSTANCE);
                } catch (Exception ex){
                    Messages.showMessageDialog(ex.getMessage(), "error massage:", Messages.getErrorIcon());
                    return;
                }
            }


            if(this.mybatisMapperCheckBox.isSelected()){
               try {
                   RepositoryInfo repositoryInfo = MyBatisPlusParser.parser(result);
                   repositoryInfo.setCodeAuthor(config.getCodeAuthor());
                   repositoryInfo.setPackagePath(CommonUtil.pathToDeclarePackage(config.getMapperPath()));
                   String generateCode = VelocityUtils.generateDao(repositoryInfo, "template/mybatis-plus/mapper.java.vm");
                   LocalFileUtils.writeFile(anActionEvent, project, CommonUtil.pathToPackage(config.getMapperPath()), repositoryInfo.getRepositoryName() + ".java", generateCode, JavaFileType.INSTANCE);

                   MapperXml mapperXml = parserMapperXml(config, result, repositoryInfo.getRepositoryName());
                   String generateXmlCode = VelocityUtils.generateMapperXml(mapperXml, "template/mybatis-plus/mapperxml.xml.vm");
                   LocalFileUtils.writeFile(anActionEvent, project, CommonUtil.pathToPackage(config.getMapperXmlPath()), repositoryInfo.getRepositoryName() + ".xml", generateXmlCode, XmlFileType.INSTANCE);

               } catch (Exception ex){
                   Messages.showMessageDialog(ex.getMessage(), "error massage:", Messages.getErrorIcon());
                   return;
               }
            }
            onOK();
        });
    }

    private boolean userOperateNoPass(Project project, CodePathConfig config, String createTableSQLText) {
        if (StringUtils.isEmpty(createTableSQLText)) {
            Messages.showMessageDialog("请正确输入MySQL建表语句！", "error massage:", Messages.getErrorIcon());
            return true;
        }

        if( !allCheck() && (jpaCheck() || myBatisCheck())){
            Messages.showMessageDialog("请正确勾选生成的代码！", "error massage:", Messages.getErrorIcon());
            return true;
        }

        if(this.jpaEntityCheck(config.getEntityPath()) || this.jpaRepositoryCheck(config.getDaoPath()) ||
        this.mybatisMapperCheck(config.getMapperPath(), config.getMapperXmlPath()) || this.mybatisPlusEntityCheck(config.getMyBatisEntityPath())) {
            configureMessageReminders(project);
            return true;
        }
        return false;
    }

    private static MapperXml parserMapperXml(CodePathConfig config, TableInfo result, String repositoryName) {
        MapperXml mapperXml = new MapperXml();
        mapperXml.setNamespace(CommonUtil.pathToDeclarePackage(config.getMapperPath()) + "." + repositoryName);
        mapperXml.setEntityName(CommonUtil.pathToDeclarePackage(config.getMyBatisEntityPath())+ "." + result.getEntityName());

        List<MapperXml.MapperXmlColumn> ids = new ArrayList<>();
        List<MapperXml.MapperXmlColumn> results = new ArrayList<>();
        List<String> columnNames = new ArrayList<>();
        result.getColumns().stream().forEach(columnInfo -> {
            MapperXml.MapperXmlColumn xmlColumn = new MapperXml.MapperXmlColumn();
            xmlColumn.setColumnName(columnInfo.getJdbcColumnName());
            xmlColumn.setProperty(columnInfo.getName());
            xmlColumn.setJdbcType(columnInfo.getJdbcType());

            columnNames.add(columnInfo.getJdbcColumnName());

            if(columnInfo.isPrimaryKey()){
                ids.add(xmlColumn);
            } else {
                results.add(xmlColumn);
            }
        });
        mapperXml.setIds(ids);
        mapperXml.setResults(results);
        mapperXml.setColumnNames(String.join(",", columnNames));
        return mapperXml;
    }


    private static void configureMessageReminders(Project project) {
        Notification notification = new Notification("Print", "table2EntitySetting",
                "检查到没有设置代码生成路径", NotificationType.INFORMATION);
        // 在提示消息中，增加一个 Action，可以通过 Action 一步打开配置界面
        notification.addAction(new OpenPathConfigSettingAction("打开配置界面"));
        Notifications.Bus.notify(notification, project);
    }


    private void onOK() {
        // add your code here
        dispose();
    }
}
